package com.lws.omapicompat

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import java.util.concurrent.Executors
import kotlin.experimental.and


class MainActivity : AppCompatActivity(), SEServiceCompat.OnConnectedListener {

    var _service: SEServiceCompat? = null
    var _session: SessionCompat? = null


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        _service = SEServiceCompat.get(this, Executors.newSingleThreadExecutor(), this)
    }


    override fun onDestroy() {
        super.onDestroy()
        _service?.shutdown()
    }

    override fun onConnected() {
        performTest()
    }


    private fun bytesToString(bytes: ByteArray): String? {
        val sb = StringBuffer()
        for (b in bytes) sb.append(String.format("%02x ", b and 0xFF.toByte()))
        return sb.toString()
    }

    private fun logText(message: String) {
        Log.e("MainActivity", "logText: $message")
    }

    private fun performTest() {
        val readers: Array<ReaderCompat> = _service!!.getReaders()
        logText("Available readers:  \n")
        for (reader in readers)
            logText(
                """	 ${
                    reader.getName().toString()
                }   - ${if (reader.isSecureElementPresent()) "present" else "absent"}"""
            )
        if (readers.size == 0) {
            logText("No reader available \n")
            return
        }
        for (reader in readers) {
            if (!reader.isSecureElementPresent()) continue
            logText(
                """
                    --------------------------------
                     Selected reader: "${reader.getName().toString()}"""".trimIndent()
            )
            try {
                _session = reader.openSession()
            } catch (e: Exception) {
                logText(e.message!!)
            }
            if (_session == null) continue
            try {
                val atr = _session!!.getATR()
                logText("""   ATR: ${atr?.let { bytesToString(it) } ?: "unavailable"}  """.trimIndent())
            } catch (e: Exception) {
                logText("""  Exception on getATR(): ${e.message}     """.trimIndent())
            }
            testBasicChannel(null)
            testBasicChannel(ISD_AID)
            testLogicalChannel(null)
            testLogicalChannel(ISD_AID)
            _session!!.close()
        }
    }

    fun testBasicChannel(aid: ByteArray?) {
        try {
            logText("""BasicChannel test: ${aid?.let { bytesToString(it) } ?: "default applet"} """.trimIndent())
            val channel: ChannelCompat? = _session!!.openBasicChannel(aid)
            val cmd = byteArrayOf(
                0x80.toByte(),
                0xCA.toByte(),
                0x9F.toByte(),
                0x7F,
                0x00
            )
            logText(""" -> ${bytesToString(cmd)}""")
            val rsp: ByteArray = channel!!.transmit(cmd)
            logText(""" <- ${bytesToString(rsp)}""")
            channel.close()
        } catch (e: Exception) {
            logText(""" Exception on BasicChannel: ${e.message} """.trimIndent())
        }
    }

    fun testLogicalChannel(aid: ByteArray?) {
        try {
            logText(""" LogicalChannel test: ${aid?.let { bytesToString(it) } ?: "default applet"}  """.trimIndent())
            val channel: ChannelCompat? = _session!!.openLogicalChannel(aid)
            val cmd = byteArrayOf(
                0x80.toByte(),
                0xCA.toByte(),
                0x9F.toByte(),
                0x7F,
                0x00
            )
            logText(""" -> ${bytesToString(cmd)}""")
            val rsp: ByteArray = channel!!.transmit(cmd)
            logText(""" <- ${bytesToString(rsp)}""")
            channel.close()
        } catch (e: Exception) {
            logText(""" Exception on LogicalChannel: ${e.message}  """.trimIndent())
        }
    }


    companion object {

        private val ISD_AID = byteArrayOf(0xA0.toByte(), 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00)
    }

}